using System;
using UtilZ.Dotnet.Ex.Model;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// Math扩展类
    /// </summary>
    unsafe public partial class MathEx
    {
        private static double _zoomPre = 0.000001d;
        /// <summary>
        /// 获取或设置缩放精度
        /// </summary>
        public static double ZoomPre
        {
            get { return _zoomPre; }
            set { _zoomPre = value; }
        }

        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="dataType">采样数据类型</param>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="startIndex">指定数据类的数据起始位置</param>
        /// <param name="length">数据字节长度</param>
        /// <param name="zoomMul">缩放倍数</param>
        public static void Zoom(TypeCode dataType, byte[] buffer, int startIndex, int length, float zoomMul)
        {
            if (zoomMul <= _zoomPre)
            {
                return;
            }

            int count;
            double temp;
            fixed (byte* waveBufferPtr = buffer)
            {
                switch (dataType)
                {
                    case TypeCode.SByte:
                        count = length;
                        sbyte* waveBytePtr = (sbyte*)(waveBufferPtr + startIndex);
                        for (int i = 0; i < count; i++)
                        {
                            temp = *waveBytePtr * zoomMul;
                            if (temp > sbyte.MaxValue)
                            {
                                *waveBytePtr = sbyte.MaxValue;
                            }
                            else if (temp < sbyte.MinValue)
                            {
                                *waveBytePtr = sbyte.MinValue;
                            }
                            else
                            {
                                *waveBytePtr = (sbyte)temp;
                            }
                            waveBytePtr++;
                        }
                        break;
                    case TypeCode.Int16:
                        count = length / 2;
                        short* waveInt16Ptr = (short*)waveBufferPtr + startIndex;
                        for (int i = 0; i < count; i++)
                        {
                            temp = *waveInt16Ptr * zoomMul;
                            if (temp > short.MaxValue)
                            {
                                *waveInt16Ptr = short.MaxValue;
                            }
                            else if (temp < short.MinValue)
                            {
                                *waveInt16Ptr = short.MinValue;
                            }
                            else
                            {
                                *waveInt16Ptr = (short)temp;
                            }
                            waveInt16Ptr++;
                        }
                        break;
                    case TypeCode.Int32:
                        count = length / 4;
                        int* waveInt32Ptr = (int*)waveBufferPtr + startIndex;
                        for (int i = 0; i < count; i++)
                        {
                            temp = *waveInt32Ptr * zoomMul;
                            if (temp > int.MaxValue)
                            {
                                *waveInt32Ptr = int.MaxValue;
                            }
                            else if (temp < int.MinValue)
                            {
                                *waveInt32Ptr = int.MinValue;
                            }
                            else
                            {
                                *waveInt32Ptr = (int)temp;
                            }

                            waveInt32Ptr++;
                        }
                        break;
                    case TypeCode.Single:
                        count = length / 4;
                        float* waveSingle32Ptr = (float*)waveBufferPtr + startIndex;
                        for (int i = 0; i < count; i++)
                        {
                            temp = *waveSingle32Ptr * zoomMul;
                            if (temp > float.MaxValue)
                            {
                                *waveSingle32Ptr = float.MaxValue;
                            }
                            else if (temp < float.MinValue)
                            {
                                *waveSingle32Ptr = float.MinValue;
                            }
                            else
                            {
                                *waveSingle32Ptr = (float)temp;
                            }

                            waveSingle32Ptr++;
                        }
                        break;
                    case TypeCode.Double:
                        count = length / 8;
                        double* waveDoublePtr = (double*)waveBufferPtr + startIndex;
                        for (int i = 0; i < count; i++)
                        {
                            temp = *waveDoublePtr * zoomMul;
                            if (temp > double.MaxValue)
                            {
                                *waveDoublePtr = double.MaxValue;
                            }
                            else if (temp < double.MinValue)
                            {
                                *waveDoublePtr = double.MinValue;
                            }
                            else
                            {
                                *waveDoublePtr = (double)temp;
                            }

                            waveDoublePtr++;
                        }
                        break;
                    default:
                        throw new NotImplementedException($"未实现的类型\"{dataType.ToString()}\"");
                }
            }

        }




        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="startIndex">指定数据类的数据起始位置</param>
        /// <param name="length">数据字节长度</param>
        /// <param name="zoomMul"></param>
        public static void ZoomInt8(byte[] buffer, int startIndex, int length, float zoomMul)
        {
            if (zoomMul <= _zoomPre || buffer == null)
            {
                return;
            }

            fixed (byte* waveBufferPtr = buffer)
            {
                float temp;
                sbyte* waveBytePtr = (sbyte*)(waveBufferPtr + startIndex);
                for (int i = 0; i < length; i++)
                {
                    temp = *waveBytePtr * zoomMul;
                    if (temp > sbyte.MaxValue)
                    {
                        *waveBytePtr = sbyte.MaxValue;
                    }
                    else if (temp < sbyte.MinValue)
                    {
                        *waveBytePtr = sbyte.MinValue;
                    }
                    else
                    {
                        *waveBytePtr = (sbyte)temp;
                    }

                    waveBytePtr++;
                }
            }
        }

        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="startIndex">指定数据类的数据起始位置</param>
        /// <param name="length">数据字节长度</param>
        /// <param name="zoomMul"></param>
        public static void ZoomInt16(byte[] buffer, int startIndex, int length, float zoomMul)
        {
            if (zoomMul <= _zoomPre || buffer == null)
            {
                return;
            }

            int count = length / 2;
            fixed (byte* waveBufferPtr = buffer)
            {
                float temp;
                short* waveInt16Ptr = (short*)waveBufferPtr + startIndex;
                for (int i = 0; i < count; i++)
                {
                    temp = *waveInt16Ptr * zoomMul;
                    if (temp > short.MaxValue)
                    {
                        *waveInt16Ptr = short.MaxValue;
                    }
                    else if (temp < short.MinValue)
                    {
                        *waveInt16Ptr = short.MinValue;
                    }
                    else
                    {
                        *waveInt16Ptr = (short)temp;
                    }
                    waveInt16Ptr++;
                }
            }
        }

        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="startIndex">指定数据类的数据起始位置</param>
        /// <param name="length">数据字节长度</param>
        /// <param name="zoomMul"></param>
        public static void ZoomInt32(byte[] buffer, int startIndex, int length, float zoomMul)
        {
            if (zoomMul <= _zoomPre || buffer == null)
            {
                return;
            }

            int count = length / 4;
            fixed (byte* waveBufferPtr = buffer)
            {
                float temp;
                int* waveInt32Ptr = (int*)waveBufferPtr + startIndex;
                for (int i = 0; i < count; i++)
                {
                    temp = *waveInt32Ptr * zoomMul;
                    if (temp > int.MaxValue)
                    {
                        *waveInt32Ptr = int.MaxValue;
                    }
                    else if (temp < int.MinValue)
                    {
                        *waveInt32Ptr = int.MinValue;
                    }
                    else
                    {
                        *waveInt32Ptr = (int)temp;
                    }
                    waveInt32Ptr++;
                }
            }
        }

        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="startIndex">指定数据类的数据起始位置</param>
        /// <param name="length">数据字节长度</param>
        /// <param name="zoomMul"></param>
        public static void ZoomFloat(byte[] buffer, int startIndex, int length, float zoomMul)
        {
            if (zoomMul <= _zoomPre || buffer == null)
            {
                return;
            }

            int count = length / 4;
            fixed (byte* waveBufferPtr = buffer)
            {
                float temp;
                float* waveSingle32Ptr = (float*)waveBufferPtr + startIndex;
                for (int i = 0; i < count; i++)
                {
                    temp = *waveSingle32Ptr * zoomMul;
                    if (temp > float.MaxValue)
                    {
                        *waveSingle32Ptr = float.MaxValue;
                    }
                    else if (temp < float.MinValue)
                    {
                        *waveSingle32Ptr = float.MinValue;
                    }
                    else
                    {
                        *waveSingle32Ptr = (float)temp;
                    }

                    waveSingle32Ptr++;
                }
            }
        }

        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="startIndex">指定数据类的数据起始位置</param>
        /// <param name="length">数据字节长度</param>
        /// <param name="zoomMul"></param>
        public static void ZoomDouble(byte[] buffer, int startIndex, int length, float zoomMul)
        {
            if (zoomMul <= _zoomPre || buffer == null)
            {
                return;
            }

            int count = length / 8;
            fixed (byte* waveBufferPtr = buffer)
            {
                double temp;
                double* waveDoublePtr = (double*)waveBufferPtr + startIndex;
                for (int i = 0; i < count; i++)
                {
                    temp = *waveDoublePtr * zoomMul;
                    if (temp > double.MaxValue)
                    {
                        *waveDoublePtr = double.MaxValue;
                    }
                    else if (temp < double.MinValue)
                    {
                        *waveDoublePtr = double.MinValue;
                    }
                    else
                    {
                        *waveDoublePtr = (double)temp;
                    }
                    waveDoublePtr++;
                }
            }
        }



        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="zoomMul"></param>
        public static void ZoomByte(SpanZ<byte> buffer, float zoomMul)
        {
            if (zoomMul <= _zoomPre)
            {
                return;
            }

            byte* waveBytePtr = buffer.DataPtr;
            for (int i = 0; i < buffer.Length; i++)
            {
                *waveBytePtr = (byte)(*waveBytePtr * zoomMul);
                waveBytePtr++;
            }
        }

        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="zoomMul"></param>
        public static void ZoomInt16(SpanZ<byte> buffer, float zoomMul)
        {
            if (zoomMul <= _zoomPre)
            {
                return;
            }

            short* waveInt16Ptr = (short*)buffer.DataPtr;
            int count = buffer.Length / 2;
            for (int i = 0; i < count; i++)
            {
                *waveInt16Ptr = (short)(*waveInt16Ptr * zoomMul);
                waveInt16Ptr++;
            }
        }

        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="zoomMul"></param>
        public static void ZoomInt32(SpanZ<byte> buffer, float zoomMul)
        {
            if (zoomMul <= _zoomPre)
            {
                return;
            }

            int count = buffer.Length / 4;
            int* waveInt32Ptr = (int*)buffer.DataPtr;
            for (int i = 0; i < count; i++)
            {
                *waveInt32Ptr = (int)(*waveInt32Ptr * zoomMul);
                waveInt32Ptr++;
            }
        }


        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="zoomMul"></param>
        public static void ZoomFloat(SpanZ<byte> buffer, float zoomMul)
        {
            if (zoomMul <= _zoomPre)
            {
                return;
            }

            int count = buffer.Length / 4;
            float* waveSingle32Ptr = (float*)buffer.DataPtr;
            for (int i = 0; i < count; i++)
            {
                *waveSingle32Ptr = (int)(*waveSingle32Ptr * zoomMul);
                waveSingle32Ptr++;
            }
        }

        /// <summary>
        /// 缩放数据幅度
        /// </summary>
        /// <param name="buffer">二进制数据缓存</param>
        /// <param name="zoomMul"></param>
        public static void ZoomDouble(SpanZ<byte> buffer, float zoomMul)
        {
            if (zoomMul <= _zoomPre)
            {
                return;
            }

            int count = buffer.Length / 8;
            double* waveDouble32Ptr = (double*)buffer.DataPtr;
            for (int i = 0; i < count; i++)
            {
                *waveDouble32Ptr = (int)(*waveDouble32Ptr * zoomMul);
                waveDouble32Ptr++;
            }
        }


    }

}
